5
תגובות

חריגת זיכרון

פתח iiddaannyy ,
יש לי את המחלקה הבאה שצובעת סינטקס:
<?php
class code_highlight {
  private $pointer = 0,
  $code = '',
  $codeHighlighted = '';
  public function setCode($code = '') {
    $code = trim($code);
    $code = str_replace("\t", '    ', $code);
    $this->code = $code;
    $this->codeHighlighted = '';
  }
  private function htmlComment_highlight($position) {
    $buffer = '<span-style="color:-green;font-style:italic;">&lt;';
    for($position++; $position < strlen($this->code) && $this->code[$position] != '>'; $position++) {
      $buffer .= $this->code[$position];
    }
    $buffer .= "&gt;</span>";
    $this->codeHighlighted .= $buffer;
    return $position;
  }
  private function htmlTag_highlight($position) {
    $buffer = '&lt;<span-style="color:-purple;">';
    $coloredTagName = false;
    for($position++; $position < strlen($this->code) && $this->code[$position] != '>'; $position++) {
      if($this->code[$position] == ' ' && !$coloredTagName) {
        $coloredTagName = true;
        $buffer.='</span>';
      }
      elseif($this->code[$position] != ' ' && $coloredTagName) {
        $attribute = '';
        for(; $position < strlen($this->code) && $this->code[$position] != '>'; $position++) {
          if($this->code[$position] != '=') {
            $attribute .= $this->code[$position];
          }
          else {
            $value= '';
            $buffer .= "<span-style=\"color:-red;\">$attribute</span>=";
            $attribute = '';
            $inQuote = false;
            $QuoteType = null;
            for($position++; $position < strlen($this->code) && $this->code[$position] != '>' && $this->code[$position] != ' '; $position++) {
              if($this->code[$position] == '"' || $this->code[$position] == '\''){
                $inQuote = true;
                $QuoteType = $this->code[$position];
                $value.=$QuoteType;
                for($position++; $position < strlen($this->code) && $this->code[$position] != '>' && $this->code[$position] != $QuoteType; $position++) {
                  $value .= $this->code[$position];
                }  
                $value.=$QuoteType;
              }
              else {
                $value .= $this->code[$position];
              }                          
            }
            $buffer .= "<span-style=\"color:-blue;\">$value</span>";
            break;          
          }

        }
        if($attribute != '') {
          $buffer.= "<span-style=\"color:-red;\">$attribute</span>";
        }
      }
      if($this->code[$position] == '>' ){
        break;
      }
      $buffer.= $this->code[$position];

    }
    if($this->code[$position] == '>' && !$coloredTagName){
      $buffer.='</span>&gt;';
      $position++;
    }
    $this->codeHighlighted .= $buffer;
    return --$position;
  }
  private function php_highlight($position) {
    $buffer = '';
    $inQuotes = false;
    $quotesType = false;
    for(; $position < strlen($this->code) &&($position > 1 && ($this->code[$position-2] != '?' || $this->code[$position-1] != '>' || $inQuotes)); $position++) {
      if ($this->code[$position] == '"' || $this->code[$position] == '\'') {
        if ($inQuotes) {
          if ($quotesType == $this->code[$position]) {
            $quotesType = false;
            $inQuotes = false;
          }
        }
        else {
          $quotesType = $this->code[$position];
          $inQuotes = true;
        }
      }
      $buffer .= $this->code[$position];
    }
    $buffer = highlight_string($buffer, true);
    $buffer = str_replace('<code><span style="color: #000000">'."\n", '<span style="color: #000000">', $buffer);
    $buffer = str_replace("\n</span>\n</code>", '</span>', $buffer);
    $buffer = str_replace('<br />', '', $buffer);
    $buffer = str_replace('<span style="color: ', '<span-style="color:-', $buffer);
    $this->codeHighlighted .= $buffer;
    return --$position;
  }
  public function highlight() {
    $this->codeHighlighted = '';
    for($pointer = 0; $pointer < mb_strlen($this->code); $pointer++) {
      $thisChar = $this->code[$pointer];
      $nextChar = ($pointer+1 == mb_strlen($this->code)) ? '' : $this->code[$pointer+1];
      if($thisChar == '<') {
        if($nextChar == '!') {
          $pointer = $this->htmlComment_highlight($pointer);
        }
        elseif ($nextChar == '?') {
          $pointer = $this->php_highlight($pointer);
        }
        else {
          $pointer = $this->htmlTag_highlight($pointer);
        }
      }
      else {
        $this->codeHighlighted .= $this->code[$pointer];
      }
    }
    $this->codeHighlighted = str_replace(' ', '&nbsp;', $this->codeHighlighted);
    $this->codeHighlighted = str_replace('<br-/>', '<br />', $this->codeHighlighted);
    $this->codeHighlighted = str_replace('<span-style="color:-', '<span style="color: ', $this->codeHighlighted);
    return nl2br("<span style=\"font-family: monospace; font-size: 13px;\">$this->codeHighlighted</span>");
  }
}
?>

היא לקוחה ברובה מהאתר php.net.

המחלקה עובדת בצורה הבאה.
1. לולאה על כל תווי הקלט.
1.1. אם זה תו פתיחה של הערה, של תג html או של קוד php, אז:
1.1.1. מפעילים את המתודה המתאימה של המחלקה (php, הערה או תג).
1.1.1.1. בתוך המתודה הזו ממשיכים לרוץ עם לולאה על הקלט (מאיפה שהגענו בלולאה בשורה 1) עד שמגיעים לתג הסגירה:
1.1.1.1.1. מוסיפים את התו הנוכחי אל המשתנה buffer.
1.1.1.2. אחרי סיום פעולת הלולאה המשתנה buffer מכיל את מה שחיפשנו במתודה (קוד php או הערה וכו').
(מכאן אתייחס רק לחלק של מתודת ה-php)
1.1.1.3. עם highlight_string צובעים את הקוד שיש ב-buffer ומכניסים לתוך buffer.
1.1.1.4. משרשרים אל משתנה המחלקה codeHighlighted את buffer
1.2. אחרת (אם זה לא תו פתיחה של הערה, של תג html או של קוד php), אז:
1.2.1. זה סתם סטרינג אז מוסיפים אותו למשתנה המחלקה codeHightlighted.
2. מחזירים כפלט את codeHighlighted.

עד כאן לאופן הפעולה של המחלקה.

הבעיה שלי היא:
Allowed memory size of 67108864 bytes exhausted (tried to allocate 66322389 bytes)

בשורה:
$this->codeHighlighted .= $buffer;


אם אני שולח html למחלקה אני מקבל חזרה את הקוד צבוע כמו שצריך והכל טוב.
אבל אם אני שולח php (או php+html) נוצרת החריגה.

מה גורם לחריגה הזו?
האם זה אופן הפעולה של המחלקה (ריצה על כל התווים של הקלט) שגורם לחריגה ב-ram?
האם זו הפונקציה highlight_string? (היא עובדת אם אני מפעיל אותה באופן חיצוני מחוץ למחלקה)

מה זה יכול להיות?


תודה מראש.

5 תשובות

avatar ענה iiddaannyy ב 31 לדצמבר 2011 #

הבעיה בשורה 101 בתוך המתודה php_highlight.

avatar ענה cthulhuil ב 31 לדצמבר 2011 #

הבעיה שלך ב-php_highlight בלולאה:

for(; $position < strlen($this->code) &&...

ובלי לעליב, המחלקה בנויה לא טוב, ולא בצורה יעילה. את ה-highlighting עושים אחרת. אבל שיהיה.

avatar ענה intval ב 01 לינואר 2012 #

החריגה נובעת מזה שיש יותר מדי נתונים ששמורים בכל מיני משתנים (בזכרון), יותר ממה שמותר לסקריפט לשמור. כמו ש ctulhu אמר, למה שלא תמשתמש במחקה קיימת? למשל geshi. אני משתמש בה.
בכל אופן, אם אתה רוצה לכתוב כזו בעצמך - לפרק קוד לחלקים עדיף עם tokenizing ולא לפי תווים.

avatar ענה iiddaannyy ב 01 לינואר 2012 #

המחלקה לא שלי, לקחתי אותה מאיזו תגובה ב-php.net.
בכל אופן תודה, אני עובד על מחלקה חדשה. :)

avatar ענה iiddaannyy ב 01 לינואר 2012 #

בניתי מחלקה חדשה.. :)
אני אפתח על זה מדריך כדי שכולם יוכלו להשתמש בה. (: